<?php

namespace app\common\library\token\driver;

use app\common\library\token\Driver;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\HttpResponseException;
use think\facade\Cache;
use think\facade\Db;
use think\Response;

/**
 * @see Driver
 */
class Mysql extends Driver
{
    /**
     * 默认配置
     * @var array
     */
    protected $options = [];

    /**
     * 构造函数
     * @access public
     * @param array $options 参数
     */
    public function __construct(array $options = [])
    {
        $db = new Db();
        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }

        if ($this->options['name']) {
            $this->handler = $db::connect($this->options['name'])->name($this->options['table']);
        } else {
            $this->handler = $db::name($this->options['table']);
        }
    }

    public function set(string $token, string $type, int $user_id, int $expire = null): bool
    {
        try {
            if (is_null($expire)) {
                $expire = $this->options['expire'];
            }
            $expireTime = $expire !== 0 ? time() + $expire : 0;
            $token      = $this->getEncryptedToken($token);
            $this->handler->insert(['token' => $token, 'type' => $type, 'user_id' => $user_id, 'create_time' => time(), 'expire_time' => $expireTime]);

            // 每隔48小时清理一次过期缓存
            $time                 = time();
            $lastCacheCleanupTime = Cache::get('last_cache_cleanup_time');
            if (!$lastCacheCleanupTime || $lastCacheCleanupTime < $time - 172800) {
                Cache::set('last_cache_cleanup_time', $time);
                $this->handler->where('expire_time', '<', time())->where('expire_time', '>', 0)->delete();
            }
            return true;
        } catch (DbException $e) {
            return false;
        }
    }

    public function get(string $token, bool $expirationException = true): array
    {
        try {
            $data = $this->handler->where('token', $this->getEncryptedToken($token))->find();
            if (!$data) {
                return [];
            }
            // 返回未加密的token给客户端使用
            $data['token'] = $token;
            // 返回剩余有效时间
            $data['expires_in'] = $this->getExpiredIn($data['expire_time'] ?? 0);
            if ($data['expire_time'] && $data['expire_time'] <= time() && $expirationException) {
                // token过期-触发前端刷新token
                $response = Response::create(['code' => 409, 'msg' => 'Token expiration', 'data' => $data], 'json');
                throw new HttpResponseException($response);
            }
            return $data;
        } catch (DataNotFoundException|ModelNotFoundException|DbException $e) {
            return [];
        }
    }

    public function check(string $token, string $type, int $user_id, bool $expirationException = true): bool
    {
        $data = $this->get($token, $expirationException);
        return $data && $data['type'] == $type && $data['user_id'] == $user_id;
    }

    /**
     * 删除数据
     * @param string $token
     * @return bool
     */
    public function delete(string $token): bool
    {
        try {
            $this->handler->where('token', $this->getEncryptedToken($token))->delete();
            return true;
        } catch (DbException $e) {
            return false;
        }
    }

    /**
     * 清除数据
     * @param string $type // 类型
     * @param int $user_id // 用户ID
     * @return bool
     */
    public function clear(string $type, int $user_id): bool
    {
        try {
            $this->handler->where('type', $type)->where('user_id', $user_id)->delete();
            return true;
        } catch (DbException $e) {
            return false;
        }
    }

}
